/**
 * \file UserStrategy.c
 * \copyright UDAN Co.,Ltd. *
 *
 * \brief 用户策略定义文件.
 *
 * * \par 修订历史:
 * | 版本号 | 修订日志 | 修改人 | 修订时间 |
 * | :--- | :--- | :--- | :--- |
 * | 0.1 | 初始版本, 完成讨论部分的定义. | UD00004 | 20170322 |
 */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "UserStrategy.h"
#include "Statistic.h"
#include "Util.h"
#include "Hv.h"
#include "RelayM.h"
#include "PowerM.h"
#include "TemperatureM.h"
#include "ChargeConnectM.h"
#include "SocCalib_Cbk.h"
#include "ChargeM.h"
#include "DischargeM.h"
#include "Diagnosis.h"
#include "FullCharge_LCfg.c"
#include "App_Types.h"
#include "RelayM_Lcfg.h"
#include "RuntimeM.h"
#include "DischargeM_Cfg.h"
#include "ChargeM_Cfg.h"

#define VCUCOMM_VOLT_4_DISPLAY(volt)    (VOLT_4_DISPLAY(volt) < 10000U ? VOLT_4_DISPLAY(volt) : 10000U)


#if ( USERSTRATEGY_DEV_ERROR_DETECT == STD_ON )
#define VALIDATE_PTR(_ptr, _api) \
    if(_ptr == NULL) { \
        Det_ReportError(MODULE_ID_USERSTRATEGY, 0U, _api, USERSTRATEGY_E_PARAM_INVALID_PTR); \
        goto cleanup; \
    }
#else
#define VALIDATE_RPTR(_ptr, _api)
#endif

UserStrategy_InnerDataType UserStrategy_innerData;


static Async_EvnetCbkReturnType UserStrategy_Poll(Async_EventType *event, uint8 byWhat);
static void safeCurrentCheck(void);

void UserStrategy_Init(Async_LooperType *looper)
{
    UserStrategy_innerData.currentIsAllowToPowerOff = TRUE;

    if (looper != NULL)
    {
        UserCurrentSensor_Init(looper);
        if (E_OK == Async_EventInit(&UserStrategy_innerData.event, looper, UserStrategy_Poll, 100UL))
        {
            (void)Async_EventRegisterToLooper(&UserStrategy_innerData.event);
        }
    }
}

static Async_EvnetCbkReturnType UserStrategy_Poll(Async_EventType *event, uint8 byWhat)
{
    (void)event;
    (void)byWhat;

    // safeCurrentCheck();

    UserStrategy_BuzzerFaultSponse();
    // UserStrategy_SleepFaultCheck();
    UserStrategy_AutoLostPower();

    return ASYNC_EVENT_CBK_RETURN_OK;
}

static void safeCurrentCheck(void)
{
    boolean flag = FALSE;
    uint32 nowTick;
    Current_CurrentType current = CurrentM_GetCurrentCalibrated(CURRENTM_CHANNEL_MAIN);

    if (!CURRENT_IS_VALID(current)) {
        flag = TRUE;
    }
    else if ((uint16)abs(current) < CURRENT_100MA_FROM_A(3U)) {
        flag = TRUE;
    }
    else {
    }

    nowTick = OSTimeGet();
    if (flag) {
        if (UserStrategy_innerData.powerOffTick == 0UL) {
            UserStrategy_innerData.powerOffTick = nowTick;
        }
        else {
            if (MS_GET_INTERNAL(UserStrategy_innerData.powerOffTick, nowTick) >= 1000UL) {
                UserStrategy_innerData.currentIsAllowToPowerOff = TRUE;
            }
        }
    }
    else {
        UserStrategy_innerData.powerOffTick = 0UL;
        UserStrategy_innerData.currentIsAllowToPowerOff = FALSE;
    }
}

//此函数底层仅调用一次，需要循环调用请在UserStrategy_SaftyOff函数中实现
boolean UserStrategy_IsSafeToOff(void) {
    boolean res = FALSE;

    if (UserStrategy_innerData.currentIsAllowToPowerOff) {
        res = TRUE;
    }
    return res;
}

boolean UserStartegy_ChargeIsAllow(void)
{
    boolean res = FALSE;

    if (Diagnosis_StartDiagIsFinish())
    {
        res = TRUE;
    }
    return res;
}

App_Tv100mvType UserStrategy_GetChargeVoltMax(void)
{
    App_Tv100mvType volt;
    Charge_ChargeType type = ChargeConnectM_GetConnectType();

    volt = PowerM_GetChargeVoltage(type);

    return volt;
}

Current_CurrentType UserStrategy_GetChargeCurrentMax(void)
{
    Current_CurrentType current;
    Charge_ChargeType type = ChargeConnectM_GetConnectType();

    if (TemperatureM_GetHeatState() != TEMPERATUREM_HEAT_STATE_NONE)
    {
        current = PowerM_GetCurrent(POWERM_CUR_CHARGE_HEATER);
    }
    else if (type == CHARGE_TYPE_DC)
    {
        current = PowerM_GetCurrent(POWERM_CUR_CHARGE_DC);
    }
    else
    {
        current = PowerM_GetCurrent(POWERM_CUR_CHARGE_AC);
    }
    return current;
}

boolean UserStartegy_GBChargeRelayIsReady(RelayM_FunctionType relayType)
{
    boolean res = FALSE;

    if (relayType == RELAYM_FN_NONE)
    {
        res = TRUE;
    }
    else if (RelayM_FunctionRelayIsEnable(relayType) == E_NOT_OK)
    {
        res = TRUE;
    }
    else if (RelayM_GetActualStatus(relayType) == RELAYM_ACTUAL_ON)
    {
        res = TRUE;
    }
    else
    {
    }
    return res;
}

App_Tv100mvType UserStrategy_GetMcuVoltage(void)
{
    return HV_GetVoltage(HV_CHANNEL_HV1);
}

uint16 UserStrategy_IsDiagHvilAbnormal(void)
{
    return 0U;
}

void UserStrategy_CheckSRS(const PwmCapture_DataType *dat)
{
    (void)dat;
    // uint8 i;
    // uint32 lowtime = PwmCapture_GetLowTime(dat);
    // if (lowtime >= 1800 && lowtime <= 2200) {
    //     ChargeM_SetOthersFaultDchargeCtl(, DIS);
    //     DischargeM_SetOthersFaultDchargeCtl();
    //     RelayM_ForceControl(RELAYM_FN_NEGTIVE_MAIN, RELAYM_FORCE_OFF); //优化断开主负
    //     for (i = 0; i < RELAYM_FN_NUM; ++i) {
    //         RelayM_ForceControl(i, RELAYM_FORCE_OFF);
    //     }
    // }
}

boolean UserStrategy_SaftyOff(RuntimeM_SignalType signal) {
    (void) signal;
    return UserStrategy_IsSafeToOff();
}

/**< 建议由连接到未连接变化时增加适当延时，保证连接状态不会突变而导致异常 */
Std_ReturnType UserStrategy_ACConnected(void)
{
    return E_NOT_OK;
}

/**< 建议由连接到未连接变化时增加适当延时，保证连接状态不会突变而导致异常 */
Std_ReturnType UserStrategy_DCConnected(void)
{
    return E_NOT_OK;
}

uint16 UserStrategy_GetCrashFault(void)
{
    return 0U;
}

void UserStrategy_FullChargeHook(void)
{
    SocDiagCalib_FullCalibCbk(DIAGNOSIS_ITEM_FULL_CHARGE, DIAGNOSIS_LEVEL_FIRST, DIAGNOSIS_EVENT_ASSERT);
    ChargeM_DiagnosisCtlDisableEventCbk(DIAGNOSIS_ITEM_FULL_CHARGE, DIAGNOSIS_LEVEL_FIRST, DIAGNOSIS_EVENT_ASSERT);
}

void UserStrategy_FullChargeReleaseHook(void)
{
    SocDiagCalib_FullCalibRelCbk(DIAGNOSIS_ITEM_FULL_CHARGE, DIAGNOSIS_LEVEL_FIRST, DIAGNOSIS_EVENT_DEASSERT);
    ChargeM_DiagnosisCtlEnableEventCbk(DIAGNOSIS_ITEM_FULL_CHARGE, DIAGNOSIS_LEVEL_FIRST, DIAGNOSIS_EVENT_DEASSERT);
}

boolean UserStrategy_RemoteBalanceConditionCheck(void){
    uint8 ret = TRUE;
    return ret;
}

void UserStrategy_StartAdhesiveDetect(void)
{

}

static void UserStrategy_BuzzerFaultSponse(void)
{
    uint8 i = 0U;
    uint8 levelFlag = 0U; // 故障报警等级记录
    uint32 lastTime = 0U;
    uint32 nowTime = OSTimeGet();
    uint32 onTime, offTime = 0U;
    static uint8 buzzerState = 0U;  // 标记蜂鸣器状态：0: 蜂鸣器关闭，1: 蜂鸣器开启
    static uint8 firstBuzzer = 0U;
    static uint8 timeFirstflag = 0U; // 响应时间第一次设置标志


    // 遍历蜂鸣鸣响10s+三级报警数组
    for (i = 0; i < (sizeof(diagnosis_level4) / sizeof(diagnosis_level4[0])); i++)
    {
        if (Diagnosis_GetLevel(diagnosis_level4[i].item) == diagnosis_level4[i].level)
        {
            levelFlag = 4U;
            if (timeFirstflag == 0)
            {
                onTime = 10U;  // 蜂鸣器响应时间设置
                offTime = 0U;
                timeFirstflag = 1;
            }
            break;
        }
    }

    if (levelFlag == 0)
    {
        // 遍历三级报警数组
        for (i = 0; i < (sizeof(diagnosis_level3) / sizeof(diagnosis_level3[0])); i++)
        {
            if (Diagnosis_GetLevel(diagnosis_level3[i].item) != diagnosis_level3[i].level)
            {
                levelFlag = 3U;
                if (timeFirstflag == 0)
                {
                    onTime = 1U;  // 蜂鸣器响应时间设置
                    offTime = 1U;
                    timeFirstflag = 1;
                }                
                break;
            }
        }
    }
    if (levelFlag == 0)
    {
        // 遍历二级报警数组
        for (i = 0; i < (sizeof(diagnosis_level2) / sizeof(diagnosis_level2[0])); i++)
        {
            if (Diagnosis_GetLevel(diagnosis_level2[i].item) != diagnosis_level2[i].level)
            {
                levelFlag = 2U;
                if (timeFirstflag == 0)
                {
                    onTime = 2U;  // 蜂鸣器响应时间设置
                    offTime = 10U;
                    timeFirstflag = 1;
                }    
                break;
            }
        }
    }

    // 如果触发故障报警
    if (levelFlag != 0) 
    {
        // 故障报警第一次进入
        if (firstBuzzer == 1)
        {
            RelayM_Control(RELAYM_FN_BUZZER, RELAYM_CONTROL_ON);
            buzzerState = 1;
        }
        // 蜂鸣器已关闭
        if (buzzerState == 0) 
        {
            if (MS_GET_INTERNAL(lastTime, nowTime) > offTime)  // 已停止*s
            {
                RelayM_Control(RELAYM_FN_BUZZER, RELAYM_CONTROL_ON);
                buzzerState = 1;            
            }
        }
        // 蜂鸣器已开启
        if (buzzerState == 1) 
        {
            if (MS_GET_INTERNAL(lastTime, nowTime) > onTime)  // 已响应*s
            {
                RelayM_Control(RELAYM_FN_BUZZER, RELAYM_CONTROL_OFF);
                buzzerState = 0;
                // 4级报警：长鸣10s切换至3级报警
                if (levelFlag == 4)
                {
                    onTime = 1U;
                    offTime = 1U; 
                }      
            }
        }
    }
    else
    {
        RelayM_Control(RELAYM_FN_BUZZER, RELAYM_CONTROL_OFF);
        buzzerState = 0;
        firstBuzzer = 0;
        timeFirstflag = 0;
        lastTime = nowTime;
    }
}

static void UserStrategy_SleepFaultCheck()
{
    uint8 i = 0U;
    static uint32 lastTime = 0U;
    uint32 nowTime = OSTimeGet();
    uint32 delay = (uint32)USERSTRATEGY_FAULT_POWER_DOWN_TIME;
    RuntimeM_RunModeType  model = RuntimeM_GetMode();
   
    // 遍历故障休眠数组
    for (i = 0; i < (sizeof(diagnosis_level4_sleep) / sizeof(diagnosis_level4_sleep[0])); i++)
    {
        if (Diagnosis_GetLevel(diagnosis_level4_sleep[i].item) == diagnosis_level4_sleep[i].level)
        {
            if (model == RUNTIMEM_RUNMODE_CALIBRATE || model == RUNTIMEM_RUNMODE_NORMAL)
            {
                if (MS_GET_INTERNAL(lastTime, nowTime) > delay)
                {
                    UserStrategy_AllRlyOff();
                    RuntimeM_RequestPowerDown();
                }
                break;
            }
            else
            {
                lastTime = nowTime;
            }
        }
        else
        {
            lastTime = nowTime;
        }
    }

}

#if USERSTRATEGY_AUTO_POWER_DOWN_EN == STD_ON
static void UserStrategy_AutoLostPower(void)
{
    static uint32 lastTime =0U;
    uint32 nowTime = OSTimeGet();
    uint32 delay = USERSTRATEGY_AUTO_POWER_DOWN_TIME;
    RuntimeM_RunModeType  model = RuntimeM_GetMode();
    Current_CurrentType current = CurrentM_GetCurrent(CURRENTM_CHANNEL_MAIN);

    if (model == RUNTIMEM_RUNMODE_CALIBRATE || model == RUNTIMEM_RUNMODE_NORMAL)
    {
        if (CurrentM_IsValidCurrent(current) && current <= CURRENT_100MA_FROM_A(USERSTRATEGY_AUTO_POWER_DOWN_CURRENT))
        {
            current = abs(current);
            if (MS_GET_INTERNAL(lastTime, nowTime) > delay)
            {
                ChargeM_SetOthersFaultChargeCtl(CHARGEM_OTHERS_FAULT_POWER_OFF, CHARGEM_CHARGE_DISABLE);
                DischargeM_SetOthersFaultDchargeCtl(DISCHARGEM_OTHERS_FAULT_POWER_OFF, CHARGEM_CHARGE_DISABLE);
                UserStrategy_AllRlyOff();
                RuntimeM_RequestPowerDown();
            }
        }
        else
        {
            lastTime = nowTime;
        }
    }
    else
    {
        lastTime = nowTime;
    }
}
#endif

static void UserStrategy_AllRlyOff(void)
{
    uint8 i;
    for (i = 0; i < RELAYM_FN_NUM; ++i) 
    {
        RelayM_ForceControl(i, RELAYM_FORCE_OFF);
    }
}